#ifndef EMITTER_RANGE_HPP
#define EMITTER_RANGE_HPP

#include <cstdlib>
#include <iostream>
using namespace std;

class EmitterRange{
    public:
    EmitterRange(float value, float deviation) :
    value(value), deviation(deviation)
    {
        recalc_factor();
        if(!random_array_initiated){
            init_random_array();
            random_array_initiated = true;
        }
    }


    EmitterRange(float value, float deviation_up, float deviation_down) :
    value(value)
    {
        //Also readjusts value
        set_deviation(deviation_up, deviation_down);

        if(!random_array_initiated){
            init_random_array();
        }
    }


    void set_deviation(float deviation){
        this->deviation = deviation;
        recalc_factor();
    }

    void set_deviation(float deviation_up, float deviation_down){
        const float max_value = value + deviation_up;
        const float min_value = value - deviation_down;

        value = (max_value + min_value)/2;
        set_deviation((deviation_up+deviation_down)/2);
    }

//    float get_ranged_value() const {
//        //Manually inlined version of get_random_float()
//        static unsigned int i = 0;
//        i = (i >= random_array_size) ? rand()%random_array_size : i;
//        return value+(random_array[i++]*factor-deviation);
//    }

    float get_ranged_value() const {
        //Manually inlined version of get_random_float()
        static unsigned int i = 0;
        i = (i >= random_array_size) ? rand()%random_array_size : i;
        const float ans = value+(random_array[i++]*factor-deviation);

//        if(ans < value-deviation || ans > value+deviation){
//            cout << "SJAKLDJAKLSjdA" << endl;
//        }
//
//        cout << ans << endl;

        return ans;
    }


    void output() const{
        #define out(x) cout << #x << ": " << x << endl
        out(value);
        out(deviation);
        out(factor);
        #undef out
    }

    private:
    void recalc_factor(){
        factor = (2.0/RAND_MAX)*deviation;
    }

    void init_random_array(){
        cout << "Initializing " << random_array_size << " random values: ";
        for(unsigned int i = 0; i < random_array_size; i++){
            random_array[i] = rand();
        }
        cout << "Done!" << endl;
    }

    //Call to this funtion takes too much time, so it's manually inlined in get_ranged_value()
    float get_random_float(){
        static unsigned int i = 0;
        if(i >= random_array_size) i = rand()%random_array_size;
        return random_array[i++];
    }

    float value;
    float deviation;
    float factor;

    //speedup teh randoms
    const static unsigned int random_array_size;
    static bool random_array_initiated;
    static float random_array[];
};

#endif // EMITTER_RANGE_HPP

